
import aei.AeRegistry
import aei.AeiService
import aei.StudySearchSchedule
import aei.StudySearchResult
import hce.HceService
import hce.core.composition.* // Composition y EventContext

class RunScheduledStudySearchJob {
    
    def aeiService
    def hceService
    
    def timeout = 60000l // execute job once in 10 seconds
    def startDelay = 60000l // empieza al minuto
    /*
    static triggers = {
        simple name:'simpleTrigger', startDelay:10000, repeatInterval: 30000, repeatCount: 10
        cron name:'cronTrigger', startDelay:10000, cronExpression: '0/6 * 15 * * ?'
        custom name:'customTrigger', triggerClass:MyTriggerClass, myParam:myValue, myAnotherParam:myAnotherValue
    }
    */
    
    def execute()
    {
        println "... .......................... ..."
        println "... RunScheduledStudySearchJob ..."
        println "... .......................... ..."
        
        def pacss = AeRegistry.list() // pacs configurados
        def schedules = StudySearchSchedule.list() // busquedas programadas
        
        def pacsErrors = [:] // Se usa al final para saber si no se pudo conectar al pacs
        // Si actualizo el pacs adentro de esta iteracion por pacs
        // me dice que fue actualizado por otra transaccion.
        // Asi que uso el pacsErrors para actualizar el pacs al finalizar la iteracion.

        pacss.each { pacs ->
        
            if (pacs.active)
            {
                schedules.each { schedule ->
                
                    if (schedule.episodioId)
                    {
                        def name = schedule.subject.identities.find{ it.purpose == 'PersonName'}
                    
                        // TODO: retries si hay un problema, cant configurable
                        
                        // Un intento con cada id, si encuentro con uno, no ejecuto los otros.
                        def iter = schedule.subject.ids.iterator()
                        while (iter.hasNext())
                        {
                            def pid = iter.next()
                            try {
                                /* busca a nivel de paciente. es para ver si el paciente esta en el pacs, no para obtener el estudio...
                                def results = aeiService.sendDICOMQuery1( pacs,
                                              ((name?.primerNombre) ? name?.primerNombre : null), // nombre 1
                                              ((name?.primerApellido) ? name?.primerApellido : null), // apellido 1
                                              pid.extension,
                                              null, //params.studyDateFrom_year  as Integer,
                                              null, //params.studyDateFrom_month as Integer,
                                              null, //params.studyDateFrom_day   as Integer,
                                              null, //params.studyDateTo_year    as Integer,
                                              null, //params.studyDateTo_month   as Integer,
                                              null //params.studyDateTo_day     as Integer
                                          )
                                */
                                 
                                // busca a nivel de estudio
                                def results = aeiService.sendDICOMQuery2(
                                    pacs,
                                    ((name?.primerNombre) ? name?.primerNombre : null), // nombre 1
                                    ((name?.primerApellido) ? name?.primerApellido : null), // apellido 1
                                    pid.extension,
                                    null, //String studyID,
                                    null, //params.studyDateFrom_year  as Integer,
                                    null, //params.studyDateFrom_month as Integer,
                                    null, //params.studyDateFrom_day   as Integer,
                                    null, //params.studyDateTo_year    as Integer,
                                    null, //params.studyDateTo_month   as Integer,
                                    null //params.studyDateTo_day     as Integer
                                )
                                
                                // Marco como que no hubo error para este pacs
                                pacsErrors[pacs] = false
                                
                                if (results.size() > 0)
                                {
                                    results.each { result ->
                                    
                                        println "   resutl: " + result
                                    
                                        
                                        // El id que se guarda en el result es el del partySelf del episodio, asi tengo 
                                        // vinculados los resultados al episodio y es mas facil mostrarlos para el episodio actual.
                                        def compo = Composition.get( schedule.episodioId )
                                        def pself = hceService.getPartySelfFromComposition( compo ) // Puede ser null si el episodio no tiene paciente, pero no estaria aca si no se hubiera identificado un paciente antes y si la busqueda programada no tuviera el episodioId seteado.
                                        
                                        
                                        // No guardar un resultado que ya se obtuvo 
                                        def resExists = StudySearchResult.withCriteria {
                                           eq('patientId', pself.externalRef.objectId.value)
                                           eq('studyDate', result['80020'])
                                        }
                                    
                                        if (resExists.size() == 0 && pself)
                                        {
                                            /*
                                             * 
                                             * 80005:ISO_IR 100, 
                                             * 80020:20010105, 
                                             * 80030:083501, 
                                             * 80050:0000000001, 
                                             * 80052:STUDY, 
                                             * 80054:SERVERAE, 
                                             * 80056:ONLINE, 
                                             * 80061:CT, 
                                             * 100010:MISTER^CT, 
                                             * 100020:2178309, 
                                             * 100032:, 
                                             * 100040:, 
                                             * 20000d:1.2.840.113619.2.30.1.1762295590.1623.978668949.886, 
                                             * 200010:40933, 
                                             * 201200:, 
                                             * 201202:, 
                                             * 201204:
                                             * ]
                                             */
                                            def ssres = new StudySearchResult
                                            (
                                                patientName:  result['100010'], // 100010 => MISTER^CT
                                                patientId:    pself.externalRef.objectId.value, //result['100020'], // FIXME: hacer que el id que se guarda sea el del partySelf del episodio, asi tengo vinculados los resutlados al episodio.
                                                birthDate:    result['100030'],
                                                sex:          result['100040'],
                                                studyDate:    result['80020'],
                                                studyId:      result['200010'],
                                                seriesNumber: result['201206'],
                                                imagesNumber: result['201208'],
                                                modalitiesInStudy: result['80061'],
                                                source:       pacs // Desde que PACS se obtuvo el resultado
                                            )

                                            if (!ssres.save())
                                            {
                                                println "   RunScheduledStuydSearch: error al salvar result " + ssres.errors
                                            }
                                        }
                                        else
                                            println "   RunScheduledStuydSearch: estudio ya encontrado"
                                    }
                                    break // no busca por otros ids
                                }
                            }
                            catch (Exception e)
                            {
                                println "   RunScheduledStuydSearch: Exception: " + e.getMessage()
                                
                                // FIXME: para ver si anda mal el QR deberia tirar la except aca
                                //        pero la catchea adentro...
                                
                                // Hubo error para este pacs
                                pacsErrors[pacs] = true
                            }
                        } // para cada id de la persona
                    } // si tengo el id del episodio en la busqueda programada
                    else
                    {
                        // busco a ver si hay un episodio para el paciente para obtener el episodioId
                        def compo = hceService.getActiveCompositionForPatient( schedule.subject )
                        
                        println "Compositio encontrado para el paciente: " + compo
                        
                        // Pude identificar el episodio al que pertenece la persona
                        // configurada en la busqueda planificada (el episodio es necesario
                        // para que los resultados se asocien al id de la persona que esta
                        // guardado en el episodio (en el partySelf.externalRef.id).
                        // Ese id es el que voy a usar para saber si tengo que mostrar los resultados
                        // de la busqueda en el episodio que esta viendo el medico.
                        // Podria obtener directamente el id del partyRef del episodio pero tengo 
                        // que asegurarme que el episodio esta activo.
                        if (compo)
                        {
                            schedule.episodioId = compo.id
                        }
                    }
                } // para cada busqueda programada
            } // si el pacs esta activo
        } // para cada pacs configurado
        
        //println "PACS ERRORS: " + pacsErrors
        
        // Veo si ocurrieron
        pacsErrors.keySet().each { pacs ->
            if (pacsErrors[pacs])
            {
                // Si de un PACS no puede tener conexion luego de X intentos 
                // configurables, que no intente conectar a ese PACS nunca mas.
                // Volveria a intentar conectarse al PACS si desde la pantalla de
                // adminsitracion de AeRegistry lo habilito.
                def maxBadCC = 5 // TODO: sacarlo de config
                
                AeRegistry.withTransaction { status ->
                
                    pacs.badConnectionCount ++
                    if (pacs.badConnectionCount > maxBadCC)
                        pacs.active = false
                        
                    if (!pacs.save(flush:true))
                        println "   RunScheduledStudySearch: ERROR al actualizar aeRegistry: " + pacs.errors
                }
                
                // Creo que salva solito al cambiarle los valores de los campos...
                // Si le hago save me dice: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect
                //if (!pacs.save())
                //    println "RunScheduledStuydSearch: error al salvar PACS " + pacs.errors
            }
            else
            {
                // Si no hubo excepcion el servidor esta online, reseteo la cuenta
                // de conecciones para decir que esta conexion funciona.
                pacs.badConnectionCount = 0 // se guarda solo!
            }
        }
    }
}
